﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Platform.Infrastructure;
using System.Linq.Expressions;

namespace Platform.ObjectModel.Design
{

	/// <summary>
	/// Auxilia na criação do schema de um documento
	/// </summary>
	/// <typeparam name="TEntity"></typeparam>
	public class SchemaBuilder<TEntity>
	{

		public SchemaBuilder( Schema schema )
		{
			this.Schema = schema;
		}

		/// <summary>
		/// Define o nome que é apresentado para o usuário do sistema
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public SchemaBuilder<TEntity> FriendlyName( string name )
		{
			this.Schema.FriendlyName = name;
			return this;
		}

		/// <summary>
		/// Define um campo do documento
		/// </summary>
		/// <typeparam name="TValue"></typeparam>
		/// <param name="getter"></param>
		/// <returns></returns>
		public FieldDescriptorBuilder Field<TValue>( Expression<Func<TEntity, TValue>> getter )
		{
			FieldDescriptorBuilder builder = null;

			this.Field<TValue>( getter, created => builder = created );

			return builder;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TValue"></typeparam>
		/// <param name="getter"></param>
		/// <param name="factory"></param>
		/// <returns></returns>
		public SchemaBuilder<TEntity> Field<TValue>( Expression<Func<TEntity, TValue>> getter, Action<FieldDescriptorBuilder> factory )
		{
			string fieldName = getter.GetPropertyName();
			FieldDescriptorBuilder builder = new FieldDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ), this.Schema );

			if ( factory != null )
				factory( builder );

			Type valueType = typeof( TValue );
			if ( valueType.Equals( typeof( DataObjectName ) ) )
				builder.Format( Globals.Formatters.DataObjectName );
			else if ( valueType.Equals( typeof( DocumentToken ) ) )
				builder.Format( Globals.Formatters.Token );

			builder.TypeOf( valueType );
			this.Schema.Fields.Add( builder.Field );
			return this;
		}




		/// <summary>
		/// 
		/// </summary>
		/// <param name="getter"></param>
		/// <returns></returns>
		//public FieldDescriptorBuilder FieldKey( Expression<Func<TEntity, string>> getter )
		//{
		//	string fieldName = getter.GetPropertyName();

		//	FieldDescriptorBuilder builder = new FieldDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ) );

		//}

		public FieldDescriptorBuilder FieldCollectionOf<TValue>( Expression<Func<TEntity, ICollection<TValue>>> getter )
		{
			string fieldName = getter.GetPropertyName();
			FieldDescriptorBuilder builder = new FieldDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ), this.Schema );
			builder.TypeOf( FieldType.Collection );
			this.Schema.Fields.Add( builder.Field );
			return builder;
		}

		//public FieldDescriptorBuilder RelateWith<TValue>( Expression<Func<TEntity, ICollection<TValue>>> getter )
		//{
		//    string fieldName = getter.GetPropertyName();
			
		//    return null;
		//}

		public FieldDescriptorBuilder RelateWith<TValue>( Expression<Func<TEntity, TValue>> fieldGetter )
			where TValue : DataObjectFlake
		{
			string fieldName = fieldGetter.GetPropertyName();

			FieldDescriptorBuilder builder = new FieldRefDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ), this.Schema );
			builder.TypeOf( FieldType.Object );

			this.Schema.Relations.Add( ( FieldRefDescriptor )builder.Field );
			return builder;
		}

		public FieldDescriptorBuilder RelateWith<TValue>( Expression<Func<TEntity, ICollection<TValue>>> fieldGetter )
			where TValue : DataObjectFlake
		{
			string fieldName = fieldGetter.GetPropertyName();

			FieldDescriptorBuilder builder = new FieldRefDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ), this.Schema );
			builder.TypeOf( FieldType.Collection );

			this.Schema.Relations.Add( ( FieldRefDescriptor )builder.Field );
			return builder;
		}

		//public FieldRefDescriptorBuilder RelateWith<TValue>( Expression<Func<TEntity, ICollection<TValue>>> fieldGetter )
		//    where TValue : IQualifiedDataObject
		//{
		//    string fieldName = fieldGetter.GetPropertyName();

		//    FieldRefDescriptorBuilder builder = new FieldRefDescriptorBuilder( new DataObjectName( fieldName, this.Schema.QualifiedName.FullName ) );
		//    builder.TypeOf( FieldType.Collection );
		//    return builder;
		//}

		/// <summary>
		/// Obtém o schema que está sendo construído
		/// </summary>
		public Schema Schema
		{ get; private set; }


		public static SchemaBuilder<TEntity> Create( DataObjectName qualifiedName )
		{
			return new SchemaBuilder<TEntity>( new Schema( qualifiedName ) );
		}
	}

	
}
